package com.ellecity06.debugtools.interceptor

import android.content.Context
import android.util.Log
import com.ellecity06.debugtools.db.DebugToolsDatabase
import com.ellecity06.debugtools.db.entity.RequestEntity
import okhttp3.Interceptor
import okhttp3.RequestBody
import okhttp3.Response
import okhttp3.ResponseBody
import okhttp3.internal.isSensitiveHeader
import okio.Buffer
import java.io.IOException

/**
 * @author ellecity06
 * @time 2023/4/20 9:49
 * @des
 */
internal class RecordInterceptor(
    private val context: Context,
    private val callback: OnInterceptorCallback = OnInterceptorCallbackImpl(),
) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val startMillis = System.currentTimeMillis()
        val request = chain.request()
        val requestBuilder = request.newBuilder()
        val url = request.url.toUrl().toString()
        //忽略拦截url
        if (callback != null && callback.isIgnoreUrl(url)) {
            return chain.proceed(request)
        }
        val method = request.method
        val requestHeaders = buildString {
            request.headers.forEach {
                append(it.first)
                append(": ")
                append(it.second)
                append("\n")
            }
        }
        //是否解析接口
        val isAnalyzeRequestBody = callback.isAnalyzeRequestBody(url)
        //是否加密接口
        val isEncryptRequestBody = callback.isEncryptRequestBody(url)
        val requestBodyStr = if (isAnalyzeRequestBody || isEncryptRequestBody) bodyToString(request.body) else "不支持查看当前内容"
        //加密请求body
        val encryptRequestBodyStr = if (isEncryptRequestBody) callback?.onRequestBodyEncrypt(
            url,
            requestBodyStr
        ) else requestBodyStr
        val requestEntity = RequestEntity()
        requestEntity.method = method
        requestEntity.host = request.url.host
        requestEntity.path = request.url.encodedPath
        requestEntity.query = request.url.query
        requestEntity.url = url
        requestEntity.requestHeader = requestHeaders
        requestEntity.requestBody = encryptRequestBodyStr
        requestEntity.decryptRequestBody = if (isEncryptRequestBody) requestBodyStr else ""
        requestEntity.code = 0
        requestEntity.sentRequestAtMillis = startMillis
        requestEntity.receivedResponseAtMillis = 0
        try {
            val response = chain.proceed(request)
            var responseBody = response.body
            val endMillis = System.currentTimeMillis()
            //是否解析接口
            val isAnalyzeResponseBody = callback.isAnalyzeResponseBody(url)
            //是否解密接口
            val isDecryptResponseBody = callback.isDecryptResponseBody(url)
            val responseBodyStr =
                if (isAnalyzeResponseBody || isDecryptResponseBody) responseBody?.string() else "不支持查看当前内容"
            val decryptResponseBodyStr = if (isDecryptResponseBody) callback.onResponseBodyDecrypt(
                url,
                responseBodyStr
            ) else ""
            val contentLength = responseBody?.contentLength()
            val mediaType = responseBody?.contentType()
            val responseHeaders = response.headers


            val code = response.code
            val sentRequestAtMillis = if (response.sentRequestAtMillis <= 0) startMillis else response.sentRequestAtMillis
            val receivedResponseAtMillis =
                if (response.receivedResponseAtMillis <= 0) endMillis else response.receivedResponseAtMillis
            val handshake = response.handshake
            val message = response.message
            val protocol = response.protocol
            requestEntity.code = code.toLong()
            requestEntity.responseBody = responseBodyStr
            requestEntity.decryptResponseBody = decryptResponseBodyStr
            requestEntity.contentLength =
                if (contentLength == -1L) (requestEntity.responseBody?.toByteArray()?.size
                    ?: 0) * 1L else contentLength
            requestEntity.decryptContentLength =
                requestEntity.decryptResponseBody?.toByteArray()?.size?.toLong() ?: 0L
            requestEntity.responseHeader = responseHeaders.toString()
            requestEntity.mediaType = mediaType?.toString()
            requestEntity.sentRequestAtMillis = sentRequestAtMillis
            requestEntity.receivedResponseAtMillis = receivedResponseAtMillis
            // 添加到数据库
            DebugToolsDatabase.getDatabase(context).getRequestDao().insert(requestEntity)

            if (isAnalyzeResponseBody || isDecryptResponseBody) {
                responseBody = ResponseBody.create(mediaType, responseBodyStr ?: "")
                return response.newBuilder().body(responseBody).build()
            }
            return response.newBuilder().build()
        } catch (e: Exception) {
            val stringBuilder = StringBuilder(e.javaClass.toString())
            e.stackTrace.forEach {
                stringBuilder.append("\n").append(it.toString())
            }
            requestEntity.errorMessage = stringBuilder.toString()
            requestEntity.sentRequestAtMillis =
                if (requestEntity.sentRequestAtMillis != null) requestEntity.sentRequestAtMillis else startMillis
            requestEntity.receivedResponseAtMillis =
                if (requestEntity.receivedResponseAtMillis!! != 0L) requestEntity.receivedResponseAtMillis else System.currentTimeMillis()
            DebugToolsDatabase.getDatabase(context).getRequestDao().insert(requestEntity)
            throw e
        }

    }

    /**
     * RequestBody 转string
     */
    private fun bodyToString(request: RequestBody?): String {
        return try {
            val buffer = Buffer()
            if (request != null) {
                request.writeTo(buffer)
            } else {
                return ""
            }
            buffer.readUtf8()
        } catch (e: IOException) {
            //"did not work"
            ""
        } catch (e: OutOfMemoryError) {
            e.localizedMessage
            ""
        } catch (e: Exception) {
            e.localizedMessage
            ""
        }

    }

    /**
     * 解密回调
     */
    interface OnInterceptorCallback {
        /**
         * 是否解析请求body
         */
        fun isAnalyzeRequestBody(url: String): Boolean

        /**
         * 是否解析返回body
         */
        fun isAnalyzeResponseBody(url: String): Boolean

        /**
         * 是否加密请求body
         */
        fun isEncryptRequestBody(url: String): Boolean

        /**
         * 是否解密返回body
         */
        fun isDecryptResponseBody(url: String): Boolean

        /**
         * 请求body加密
         */
        fun onRequestBodyEncrypt(url: String, body: String?): String?

        /**
         * 返回body解密
         */
        fun onResponseBodyDecrypt(url: String, body: String?): String?

        /**
         * 忽略url
         */
        fun isIgnoreUrl(url: String): Boolean
    }

    open class OnInterceptorCallbackImpl : OnInterceptorCallback {
        override fun isAnalyzeRequestBody(url: String): Boolean = true

        override fun isAnalyzeResponseBody(url: String): Boolean = true

        override fun isEncryptRequestBody(url: String): Boolean = false

        override fun isDecryptResponseBody(url: String): Boolean = false

        override fun onRequestBodyEncrypt(url: String, body: String?): String? {
            return body
        }

        override fun onResponseBodyDecrypt(url: String, body: String?): String? {
            return ""
        }

        override fun isIgnoreUrl(url: String): Boolean = false

    }
}